package com.gqr.jmm;

/**
 * Copyright (C), 2020-2024,gqr
 * FileName:FieldVisibility
 * author:guqingrong
 * Date:2024-05-01 21:12
 * Description:演示可见性带来的问题
 * History:
 * <author>    <time>    <version>    <desc>
 * 作者姓名     修改时间     版本号        描述
 */
public class FieldVisibility {
    //volatile关键字的性质 会强制线程每次读取变量的值都是已经修改过的最新的值
     int a = 1;
     int b = 2;
     int c = 2;
     int d = 2;



    private void change() {
        a = 3;
        b = 4;
        c = 5;
        synchronized (this){
            d = 6;

        }
    }


    private void print() {
        // 可能出现的结果
        // 1 a=3 b=3
        // 2 a=1 b=2
        // 3 a=3 b=2
        // 4 a=1 b=3(概率低)  多线程之间数据没有实时同步造成的 线程1赋值
        // 对于线程2而言b看到了真实的值3  而去找a的时候 a还没有完全同步过来 找到的是a的原始值1 而不是3
        // 没给b加volatile，那么有可能出现a=1 b=3 因为a虽然被修改了，但是其他线程不可见，而b恰好其他线程可见，所以造成此结果

        /**
         * 近朱者赤：给b加了volatile。不仅b被影响，也可以实现轻量级同步
         * b之前的写入（对应代码b=a）对读取b后的代码都可见，所以在writerThread里对a赋值，一定会对readerThread里的读取可见
         * 所以这里的a即使不加volatile，只要b读到是3，就可以有h-b原则保证了读取到的都是3而不可能读取到1
         */
        synchronized (this){
            int aa = a;

        }
        int bb = b;
        int cc = c;
        int dd = d;
        System.out.println("b = " + b + ";a = " + a);
    }

    public static void main(String[] args) {
        while (true) {
            FieldVisibility test = new FieldVisibility();
            new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    test.change();
                }
            }).start();

            new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    test.print();
                }
            }).start();
        }

    }


}
